package ru.alperez.blurringtest;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import ru.alperez.blurringtest.util.SystemUiHider;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.Button;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

/**
 * An example full-screen activity that shows and hides the system UI (i.e.
 * status bar and navigation/system bar) with user interaction.
 * 
 * @see SystemUiHider
 */
public class MainActivity extends Activity {
	/**
	 * Whether or not the system UI should be auto-hidden after
	 * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
	 */
	private static final boolean AUTO_HIDE = true;

	/**
	 * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
	 * user interaction before hiding the system UI.
	 */
	private static final int AUTO_HIDE_DELAY_MILLIS = 3000;

	/**
	 * If set, will toggle the system UI visibility upon interaction. Otherwise,
	 * will show the system UI visibility upon interaction.
	 */
	private static final boolean TOGGLE_ON_CLICK = true;

	/**
	 * The flags to pass to {@link SystemUiHider#getInstance}.
	 */
	private static final int HIDER_FLAGS = SystemUiHider.FLAG_HIDE_NAVIGATION;

	/**
	 * The instance of the {@link SystemUiHider} for this activity.
	 */
	private SystemUiHider mSystemUiHider;

	private ViewGroup vContentContainer;
	private ImageView imgContent;
	private TextView txtContent;
	
	private SeekBar mSeekBar;
	private TextView txtRadius;
	private TextView txtTime;
	private CheckedTextView cbDownscale;
	private Button btnRenderscript;
	private Button btnJava;
	
	private Bitmap mOriginalBitmap;
	private Bitmap mProcessedBitmap;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);

		final ViewGroup controlsView = (ViewGroup) findViewById(R.id.fullscreen_content_controls);
		vContentContainer = (ViewGroup) findViewById(R.id.fullscreen_content);
		imgContent = (ImageView) findViewById(R.id.content_image);
		txtContent = (TextView) findViewById(R.id.content_text);
		mSeekBar = (SeekBar) findViewById(R.id.seekbar);
		txtRadius = (TextView) findViewById(R.id.txt_radius);
		txtTime = (TextView) findViewById(R.id.txt_time);
		cbDownscale = (CheckedTextView) findViewById(R.id.cb_downscale);
		btnRenderscript = (Button) findViewById(R.id.btn_renderscript);
		btnJava = (Button) findViewById(R.id.btn_java);
		controlsView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
			
			@Override
			public void onGlobalLayout() {
				int w = Math.max(btnRenderscript.getMeasuredWidth(), btnJava.getMeasuredWidth());
				((ViewGroup.LayoutParams) btnRenderscript.getLayoutParams()).width = w;
				((ViewGroup.LayoutParams) btnJava.getLayoutParams()).width = w;
				controlsView.requestLayout();
				controlsView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
			}
		});
		

		// Set up an instance of SystemUiHider to control the system UI for
		// this activity.
		mSystemUiHider = SystemUiHider.getInstance(this, vContentContainer, HIDER_FLAGS);
		mSystemUiHider.setup();
		mSystemUiHider.setOnVisibilityChangeListener(new SystemUiHider.OnVisibilityChangeListener() {
					// Cached values.
					int mControlsHeight;
					int mShortAnimTime;

					@Override
					@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
					public void onVisibilityChange(boolean visible) {
						if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
							// If the ViewPropertyAnimator API is available
							// (Honeycomb MR2 and later), use it to animate the
							// in-layout UI controls at the bottom of the
							// screen.
							if (mControlsHeight == 0) {
								mControlsHeight = controlsView.getHeight();
							}
							if (mShortAnimTime == 0) {
								mShortAnimTime = getResources().getInteger(
										android.R.integer.config_shortAnimTime);
							}
							controlsView
									.animate()
									.translationY(visible ? 0 : mControlsHeight)
									.setDuration(mShortAnimTime);
						} else {
							// If the ViewPropertyAnimator APIs aren't
							// available, simply show or hide the in-layout UI
							// controls.
							controlsView.setVisibility(visible ? View.VISIBLE
									: View.GONE);
						}

						if (visible && AUTO_HIDE) {
							// Schedule a hide().
							delayedHide(AUTO_HIDE_DELAY_MILLIS);
						}
					}
				});

		// Set up the user interaction to manually show or hide the system UI.
		txtContent.setOnClickListener(mContentClickListener);

		// Upon interacting with UI controls, delay any scheduled hide()
		// operations to prevent the jarring behavior of controls going away
		// while interacting with the UI.
		controlsView.setOnTouchListener(new View.OnTouchListener() {
			@Override
			public boolean onTouch(View view, MotionEvent motionEvent) {
				if (AUTO_HIDE) {
					delayedHide(AUTO_HIDE_DELAY_MILLIS);
				}
				return true;
			}
		});
		mSeekBar.setOnTouchListener(mDelayHideTouchListener);
		txtRadius.setOnTouchListener(mDelayHideTouchListener);
		txtTime.setOnTouchListener(mDelayHideTouchListener);
		cbDownscale.setOnTouchListener(mDelayHideTouchListener);
		btnJava.setOnTouchListener(mDelayHideTouchListener);
		btnRenderscript.setOnTouchListener(mDelayHideTouchListener);
		
		mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
			
			@Override
			public void onStopTrackingTouch(SeekBar seekBar) { }
			
			@Override
			public void onStartTrackingTouch(SeekBar seekBar) { }
			
			@Override
			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
				if (fromUser && mOriginalBitmap != null) {
					addBlurRequestToQueue(progress);
				}
			}
		});
		
		cbDownscale.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				cbDownscale.setChecked(!cbDownscale.isChecked());
				
				
				
			}
		});
	}
	
	@Override
	protected void onStart() {
		super.onStart();
		if (mOriginalBitmap == null) {
			mOriginalBitmap = (Bitmap) getLastNonConfigurationInstance();
		}
		if (mOriginalBitmap != null) {
			imgContent.setImageBitmap(mOriginalBitmap);
		} else {
			//--- First time start ---
			new AsyncTask<Void, Void, Bitmap>() {

				@Override
				protected Bitmap doInBackground(Void... params) {
					Bitmap ret = null;
					try {
						Bitmap bm = BitmapFactory.decodeStream(MainActivity.this.getAssets().open("image.jpg"));
						ret = bm.copy(Bitmap.Config.ARGB_8888, true);
					} catch(IOException e) {
						ret = null;
					}
					return ret;
				}
				protected void onPostExecute(Bitmap result) {
					mOriginalBitmap = result;
					if (result != null) {
						imgContent.setImageBitmap(mOriginalBitmap);
					}
				};
			}.execute();
		}
	}
	
	@Override
	public Object onRetainNonConfigurationInstance() {
		return mOriginalBitmap;
	}
	

	@Override
	protected void onPostCreate(Bundle savedInstanceState) {
		super.onPostCreate(savedInstanceState);

		// Trigger the initial hide() shortly after the activity has been
		// created, to briefly hint to the user that UI controls
		// are available.
		delayedHide(100);
	}

	View.OnClickListener mContentClickListener = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			if (TOGGLE_ON_CLICK) {
				if ((!mSystemUiHider.isVisible() && (mOriginalBitmap != null)) || mSystemUiHider.isVisible()) {
					mSystemUiHider.toggle();
				}
			} else {
				if (mOriginalBitmap != null) {
					mSystemUiHider.show();
				}
			}
		}
	};
	
	/**
	 * Touch listener to use for in-layout UI controls to delay hiding the
	 * system UI. This is to prevent the jarring behavior of controls going away
	 * while interacting with activity UI.
	 */
	View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
		@Override
		public boolean onTouch(View view, MotionEvent motionEvent) {
			if (AUTO_HIDE) {
				delayedHide(AUTO_HIDE_DELAY_MILLIS);
			}
			return false;
		}
	};

	Handler mHideHandler = new Handler();
	Runnable mHideRunnable = new Runnable() {
		@Override
		public void run() {
			mSystemUiHider.hide();
		}
	};

	/**
	 * Schedules a call to hide() in [delay] milliseconds, canceling any
	 * previously scheduled calls.
	 */
	private void delayedHide(int delayMillis) {
		mHideHandler.removeCallbacks(mHideRunnable);
		mHideHandler.postDelayed(mHideRunnable, delayMillis);
	}


	/************************* Methods to handle queue of tasks for blurring *************************************/
	private Vector<Integer> mBlurRequestQueue = new Vector<Integer>();
	private PerformBlurTask mPerformBlurTask;
	
	private int addBlurRequestToQueue(int radius) {
		mBlurRequestQueue.addElement(Integer.valueOf(radius));
		checkQueAndHandleBlurRequest();
		return mBlurRequestQueue.size();
	}
	
	private boolean checkQueAndHandleBlurRequest() {
		if (mBlurRequestQueue.size() > 0 && mPerformBlurTask == null) {
			mPerformBlurTask = new PerformBlurTask();
			mPerformBlurTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mOriginalBitmap);
			txtContent.setText(Integer.toString(mBlurRequestQueue.size()));
			return true;
		}
		return false;
	}
	
	private class PerformBlurTask extends AsyncTask<Bitmap, Void, Map<String, Object>> {
		private int mBlurArg = -1;
		@Override
		protected void onPreExecute() {
			if (mBlurRequestQueue.size() > 0) {
				mBlurArg = mBlurRequestQueue.elementAt(0);
				mBlurRequestQueue.removeElementAt(0);
			}
		}
		
		@Override
		protected Map<String, Object> doInBackground(Bitmap... params) {
			if (mBlurArg < 0) {
				return null;
			}
			Bitmap bmp = params[0];
			if (mProcessedBitmap == null) {
				mProcessedBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);
				//mProcessedBitmap = mOriginalBitmap;
			}
			
			long time = System.currentTimeMillis();
			Rect window = new Rect(bmp.getWidth()/5, bmp.getHeight()/3, 4*bmp.getWidth()/5, 2*bmp.getHeight()/3);
			Bitmap blurredImage = Blurrer.getInstance(MainActivity.this).blurImage(null, bmp, mProcessedBitmap, window,  new int[]{mBlurArg, mBlurArg, mBlurArg}, cbDownscale.isChecked() ? 2 : 1, true);
			
			Map<String, Object> ret = new HashMap<String, Object>();
			ret.put("time", Integer.valueOf((int)(System.currentTimeMillis() - time)));
			ret.put("image", blurredImage);
			return ret;
		}
		
		@Override
		protected void onPostExecute(Map<String, Object> result) {
			mPerformBlurTask = null;
			if (result != null) {
				txtRadius.setText(Integer.toString(mBlurArg));
				txtTime.setText(((Integer) result.get("time")).toString()+"ms");
				imgContent.setImageBitmap((Bitmap) result.get("image"));
				
				checkQueAndHandleBlurRequest();
			}
		}
	}
}
